package com.cskaoyan.wordmemorize.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cskaoyan.wordmemorize.converter.ReviewConverter;
import com.cskaoyan.wordmemorize.dao.entity.*;
import com.cskaoyan.wordmemorize.dao.mapper.*;
import com.cskaoyan.wordmemorize.dto.admin.PageDTO;
import com.cskaoyan.wordmemorize.dto.app.UserCheckinDTO;
import com.cskaoyan.wordmemorize.dto.app.UserCheckinStatisticsDTO;
import com.cskaoyan.wordmemorize.request.PageRequest;
import com.cskaoyan.wordmemorize.request.UserCheckinCommand;
import com.cskaoyan.wordmemorize.service.UserCheckinService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.util.Comparator;
import java.util.List;


@Service
public class UserCheckinServiceImpl implements UserCheckinService {
    @Resource
    private UserCheckinMapper userCheckinMapper;
    @Resource
    private UserCheckinStatisticsMapper userCheckinStatisticsMapper;
    @Resource
    private UserVocBoundStatisticsMapper userVocBoundStatisticsMapper;
    @Resource
    private UserMapper userMapper;
    @Resource
    private LevelMapper levelMapper;
    @Resource
     private ReviewConverter reviewConverter;
    // 下载所有用户打卡数据
    @Override
    public PageDTO<UserCheckinDTO> getCheckInData(PageRequest pageRequest, Long userId) {
         //分页参数
         Page<UserCheckinDO> page = new Page<>(pageRequest.getPageNum(), pageRequest.getCount());
         //新建个条件构造器
         LambdaQueryWrapper<UserCheckinDO> wrapper = new LambdaQueryWrapper<>();
         wrapper.eq(UserCheckinDO::getUserId, userId);
         // 分页查询
         Page<UserCheckinDO> result = userCheckinMapper.selectPage(page, wrapper);
         // 将查询结果封装成 PageDTO
         PageDTO<UserCheckinDTO> userCheckinDTOPageDTO = reviewConverter.userCheckinPage2PageDTO(result.getRecords(), result.getTotal());
         // 返回结果
         return userCheckinDTOPageDTO;
    }
    //判断打卡日期是否是今天之后的日期
    private boolean isAfterToday(LocalDate signDate) {
        return signDate.isAfter(LocalDate.now());
    }

    // 同步用户打卡数据
    @Transactional
    @Override
    public UserCheckinStatisticsDTO checkin(UserCheckinCommand command) {
        Long userId = Long.parseLong(command.getUserId());
        LocalDate signDate = command.getSignDate();
        // 判断日期是否是今天之后的日期
        if (isAfterToday(signDate)) {
            // 签到日期是今天之后的日期，不允许签到
            return new UserCheckinStatisticsDTO();
        }
        int type = command.getType();
        // 1. 检查是否已签到
        if (userCheckinMapper.existsByUserIdAndSignDate(userId, signDate)) {
            // 已签到
            return new UserCheckinStatisticsDTO();
        }

        // 2. 处理连续签到段号
        Long stickNo = handleStickNo(userId, signDate, type);
         if (stickNo == -1L) {
            // 补签不参与连续签到计算
            stickNo = -1L;
        }
         if (stickNo == 0L){
            // 重新开始连续签到，生成一个新的唯一值
               //默认值为1
             if (userCheckinMapper.getMaxStickNo(userId) == null) {
                 stickNo = 1L;
             }
             else{
                 // 获取最大段号并生成唯一值
                 stickNo = userCheckinMapper.getMaxStickNo(userId) + 1L;
             }
        }

        // 3. 创建签到记录
        UserCheckinDO checkin = new UserCheckinDO();
        checkin.setUserId(userId);
        checkin.setSignDate(signDate);
        checkin.setType(type);
        checkin.setStickNo(stickNo);
        userCheckinMapper.insert(checkin);

        // 4. 更新签到统计
        UserCheckinStatisticsDO statistics = updateCheckinStatisticsDO(userId, signDate, stickNo,type);

        // 5. 奖励单词上限
        int rewardAmount = 10; // 每次签到奖励10个单词上限
        rewardWordLimit(userId, rewardAmount);

        // 6. 检查并更新用户等级
        checkAndUpdateUserLevel(userId, statistics);

        UserCheckinStatisticsDTO statisticsDTO = reviewConverter.userCheckinStatisticsDO2DTO(statistics);
//        7.创建个UserCheckinStatisticsDTO对象并且进行赋值
//        UserCheckinStatisticsDTO statisticsDTO = new UserCheckinStatisticsDTO();
//        statisticsDTO.setId(statistics.getId().toString());
//        statisticsDTO.setUserId(userId.toString());
//        statisticsDTO.setTotalDays(statistics.getTotalDays());
//        statisticsDTO.setMaxContinuousDays(statistics.getMaxContinuousDays());
//        statisticsDTO.setCurContinuousDays(statistics.getCurContinuousDays());
//        statisticsDTO.setMaxContinuousStartDate(statistics.getMaxContinuousStartDate());
//        statisticsDTO.setCurContinuousStartDate(statistics.getCurContinuousStartDate());
//        statisticsDTO.setTotalTime("0");

        // 8. 返回统计DTO
        return statisticsDTO;
    }


    // 处理连续签到段号
    private Long handleStickNo(Long userId, LocalDate signDate, int type) {
        // 补签不参与连续签到计算
        if (type == 2) {
            return -1L; // 使用特殊值表示补签
        }

        // 检查前一天是否有正常签到（只检查正常签到，补签不算连续）
        LocalDate previousDay = signDate.minusDays(1);
        UserCheckinDO prevCheckin = userCheckinMapper.findByUserIdAndSignDateAndType(userId, previousDay, 1);

        // 如果前一天有正常签到，使用相同的段号
        if (prevCheckin != null) {
            return prevCheckin.getStickNo();
        }

        // 新连续签到段，返回特殊标记（实际插入后会更新为ID）
        return 0L; // 临时值，插入后会更新为实际ID
    }

    // 更新签到统计
    private UserCheckinStatisticsDO updateCheckinStatisticsDO(Long userId, LocalDate signDate, Long stickNo,int type) {
        // 获取或创建用户统计记录
        UserCheckinStatisticsDO statistics = userCheckinStatisticsMapper.findByUserId(userId);
         // 如果统计记录不存在，创建新记录
        if (statistics == null) {
            //创建新的
            UserCheckinStatisticsDO newStatistics = new UserCheckinStatisticsDO();
            newStatistics.setUserId(userId);
            newStatistics.setTotalDays(1);
            newStatistics.setMaxContinuousDays(1);
            newStatistics.setCurContinuousDays(1);
            newStatistics.setMaxContinuousStartDate(signDate);
            newStatistics.setCurContinuousStartDate(signDate);
            userCheckinStatisticsMapper.insert(newStatistics);
             return newStatistics;
        }else {
            // 更新总签到天数
            statistics.setTotalDays(statistics.getTotalDays() + 1);
            // 处理连续签到天数
              //正常签到
            if (type == 1){
                //补签不影响连续签到
                if (stickNo == -1L) {

                }
                // 重新开始连续签到
                else if(stickNo == 0L){
                    statistics.setCurContinuousDays(1);
                    statistics.setCurContinuousStartDate(signDate);
                }
                else{
                    // 继续保持当前连续签到
                    statistics.setCurContinuousDays(statistics.getCurContinuousDays() + 1);
                    // 更新最大连续签到记录
                    if (statistics.getCurContinuousDays() > statistics.getMaxContinuousDays()) {
                        statistics.setMaxContinuousDays(statistics.getCurContinuousDays());
                        statistics.setMaxContinuousStartDate(statistics.getCurContinuousStartDate());
                    }
                }
            }
            // 更新数据库
            userCheckinStatisticsMapper.update(statistics,null);
            return statistics;
        }
    }

    // 奖励单词上限
    private void rewardWordLimit(Long userId, int rewardAmount) {
        //创建条件构造器
//         QueryWrapper<UserVocBoundStatisticsDO> queryWrapper = new QueryWrapper<>();
//         queryWrapper.eq(UserVocBoundStatisticsDO::getUserId, userId);
        // 获取用户单词上限统计
        UserVocBoundStatisticsDO boundStats = userVocBoundStatisticsMapper.selectByUserId(userId);

        if (boundStats == null) {
            // 创建新记录
            boundStats = new UserVocBoundStatisticsDO();
            boundStats.setUserId(userId);
            boundStats.setTotal(rewardAmount);
            boundStats.setAvailable(rewardAmount);
            userVocBoundStatisticsMapper.insert(boundStats);
        } else {
            // 更新现有记录
            boundStats.setTotal(boundStats.getTotal() + rewardAmount);
            boundStats.setAvailable(boundStats.getAvailable() + rewardAmount);
            boundStats.setFree(boundStats.getFree() + rewardAmount);
            userVocBoundStatisticsMapper.update(boundStats, null);
        }
    }

    // 检查并更新用户等级
    private void checkAndUpdateUserLevel(Long userId, UserCheckinStatisticsDO statistics) {
        UserDO user = userMapper.selectById(userId);
        if (user == null) return;

        // 获取所有等级配置
        List<LevelDO> levels = levelMapper.selectList(null);
        // 按等级值升序排列
        levels.sort(Comparator.comparingInt(LevelDO::getLevelValue));

        int currentLevel = user.getLevelValue() != null ? user.getLevelValue() : 0;
        int newLevel = currentLevel;
        LocalDate now = LocalDate.now();

        // 1. 处理前6级（累计签到升级）
        if (currentLevel < 6) {
            for (LevelDO level : levels) {
                if (level.getLevelValue() > 6)
                    break;

                // 检查是否达到升级条件
                if (statistics.getTotalDays() >= level.getCheckInDays() &&
                        level.getLevelValue() > currentLevel) {
                    newLevel = level.getLevelValue();
                }
            }
        }

        // 2. 处理6级及以上的升级（连续签到升级）
        if (currentLevel >= 6 || newLevel == 6) {
            for (LevelDO level : levels) {
                if (level.getLevelValue() <= 6) continue;

                // 检查是否达到连续签到升级条件
                if (statistics.getMaxContinuousDays() >= level.getCheckInDays() &&
                        level.getLevelValue() > newLevel) {
                    newLevel = level.getLevelValue();
                }
            }
        }


        // 4. 更新用户等级
        if (newLevel > currentLevel) {
            user.setLevelValue(newLevel);
            user.setLevelDate(now);
            userMapper.update(user,null);
        }
    }
    @Override
    public UserCheckinStatisticsDTO getUserCheckinStatistics(Long userId) {
        LambdaQueryWrapper<UserCheckinStatisticsDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserCheckinStatisticsDO::getUserId,userId);
        UserCheckinStatisticsDO statistics = userCheckinStatisticsMapper.selectOne(wrapper);
        //进行转化
        UserCheckinStatisticsDTO userCheckinStatisticsDTO = reviewConverter.userCheckinStatisticsDO2DTO(statistics);
        return userCheckinStatisticsDTO;
    }

    @Override
    public UserCheckinStatisticsDTO getUserContinuousCheckinInfo(Long userId) {
        return null;
    }

    @Override
    public int userResignCard(Long userId) {
        //判断当前用户是否有补签卡
        if (userMapper.selectById(userId).getHasSignCard() == 1){
            UserDO userDO = new UserDO();
            userDO.setHasSignCard(0);
            userDO.setId(userId);
            userMapper.updateById(userDO);
            //增加单词上限
            rewardWordLimit(userId,10);
            return 1;
        }
        else
        {
            return 0;
        }
    }
}
